﻿//*********************************************************************
//
//  文件名：SpecialMainService
//
//  作者： LW
//
//  作用：
//
//  日期：2015/9/21 9:45:39
//
//*********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Framework.Common.Paged;
using YouTravel.QueryModels;
using YouTravel.DomainModels;
using EntityFramework.Data.Core;
using IRepositories.Core;
using Framework.Common;
using YouTravel.ViewModels;
using Framework.Common.Exceptions;
using YouTravel.Framework.ResourceMessage;
using YouTravel.Framework.Enums;
using System.IO;
using YouTravel.Framework.Const;
using System.Data.Entity;

namespace YouTravel.DomainService
{
    /// <summary>
    /// SpecialMainService
    /// 专线管控
    /// </summary>
    public class SpecialService : ISpecialService
    {
        //专线资质授权号Header
        private const string SPECIALCODEHEADER = "YTSP";
        //合同编号Header
        private const string CONTRACTCODEHEADER = "YTHT";

        readonly IEFRepository<Special> _specialMainRepository;
        readonly IEFRepository<Branch> _baranchRepository;
        readonly IEFRepository<User> _userRepository;
        readonly IEFRepository<Contract> _contractRepository;
        readonly IEFRepository<Invoice> _invoiceRepository;
        readonly IEFRepository<Gathering> _gatheringRepository;
        readonly IEFRepository<Payment> _paymentRepository;
        readonly IEFRepository<Menu> _menuRepository;
        readonly IUnitOfWork _db;

        public SpecialService(IUnitOfWork db,
            IEFRepository<Special> specialMainRepository,
            IEFRepository<Branch> baranchRepository,
            IEFRepository<User> userRepository,
            IEFRepository<Contract> contractRepository,
            IEFRepository<Invoice> invoiceRepository,
            IEFRepository<Gathering> gatheringRepository,
            IEFRepository<Payment> paymentRepository,
            IEFRepository<Menu> menuRepository)
        {
            this._specialMainRepository = specialMainRepository;
            this._baranchRepository = baranchRepository;
            this._userRepository = userRepository;
            this._contractRepository = contractRepository;
            this._invoiceRepository = invoiceRepository;
            this._gatheringRepository = gatheringRepository;
            this._paymentRepository = paymentRepository;
            this._menuRepository = menuRepository;

            this._userRepository.SetDbContext(db);
            this._contractRepository.SetDbContext(db);
            this._specialMainRepository.SetDbContext(db);
            this._menuRepository.SetDbContext(db);
            this._db = db;
        }

        /// <summary>
        /// 专线列表
        /// </summary>
        /// <param name="queryCond">查询条件</param>
        /// <returns></returns>
        public CustomPagedList<SpecialViewModel> GetList(PagedParam<SpecialMainQuery> queryCond)
        {
            //只有分社才能查询
            if (queryCond.QueryDto.BranchID.HasValue)
            {
                var branch = this._baranchRepository.Find(c => c.ID == queryCond.QueryDto.BranchID);
                if (branch.Type != Framework.Enums.BranchType.Branch)
                { throw new DataOperationPermissions("非分社不能使用该功能"); }
            }

            List<OrderDto> order = new List<OrderDto>();
            order.Add(new OrderDto() { OrderField = "UpdateTime", OrderSort = "desc" });
            queryCond.OrderListDto = order;

            var tmp = _specialMainRepository.GetModel().Include(c => c.SpecialCapital)
                .GetPagedList(queryCond.PageDto.PageNo, queryCond.PageDto.PageSize,
                BuildQueryCondition(queryCond.QueryDto),
                queryCond.SortField).ToCustomPagedList<Special, SpecialViewModel>((u) =>
                {
                    var s = u.MapNew<Special, SpecialViewModel>("Balance");
                    s.Balance = u.SpecialCapital == null ? 0M : u.SpecialCapital.Balance;
                    return s;
                });
            return tmp;
        }

        private Func<IQueryable<Special>, IQueryable<Special>> BuildQueryCondition(SpecialMainQuery queryCond)
        {
            return (query) =>
            {
                if (queryCond != null)
                {
                    if (queryCond.BranchID.HasValue)
                        query = query.Where(c => c.BranchId == queryCond.BranchID.Value);
                    if (queryCond.Status.HasValue)
                        query = query.Where(c => c.Status == queryCond.Status);
                    if (!string.IsNullOrWhiteSpace(queryCond.NameOrChargeName))
                        query = query.Where(c => c.Name.Contains(queryCond.NameOrChargeName) || c.ChargeName.Contains(queryCond.NameOrChargeName));
                }
                return query;
            };

        }

        /// <summary>
        /// 专线创建
        /// </summary>
        /// <param name="model">model</param>
        public void CreateSpecial(SpecialCreateViewModel model)
        {
            #region valid

            if (string.IsNullOrWhiteSpace(model.Name))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "专线名称"));
            else
                if (!model.Name.ValidateLen(50))
                    throw new DataValidationException("专线名称长度在1-50个字符");

            if (string.IsNullOrWhiteSpace(model.ChargeName))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "负责人姓名"));
            else
                if (!model.ChargeName.ValidateLen(20))
                    throw new DataValidationException("负责人姓名长度在1-20个字符");

            if (string.IsNullOrWhiteSpace(model.ChargePhone))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "负责人手机"));
            else
                if (!model.ChargePhone.ValidateLen(11))
                    throw new DataValidationException("负责人手机长度在1-11个字符");

            if (string.IsNullOrWhiteSpace(model.ChargePaperType))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "负责人证件名称"));
            else
                if (!model.ChargePaperType.ValidateLen(20))
                    throw new DataValidationException("负责人证件名称长度在1-20个字符");

            if (string.IsNullOrWhiteSpace(model.ChargePaperNumber))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "负责人证件号"));
            else
                if (!model.ChargePaperNumber.ValidateLen(30))
                    throw new DataValidationException("负责人证件号长度在1-30个字符");

            if (string.IsNullOrWhiteSpace(model.ChargeBankNumber))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "负责人银行卡号"));
            else
                if (!model.ChargeBankNumber.ValidateLen(20))
                    throw new DataValidationException("负责人银行卡号长度在1-20个字符");

            if (string.IsNullOrWhiteSpace(model.ChargeBank))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "开户银行"));
            else
                if (!model.ChargeBank.ValidateLen(30))
                    throw new DataValidationException("开户银行长度在1-30个字符");

            if (string.IsNullOrWhiteSpace(model.CompanyNumber))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "悠程公司卡号"));
            else
                if (!model.CompanyNumber.ValidateLen(20))
                    throw new DataValidationException("悠程公司卡号长度在1-20个字符");

            if (string.IsNullOrWhiteSpace(model.CompanyBank))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "悠程公司卡开户银行"));
            else
                if (!model.CompanyBank.ValidateLen(30))
                    throw new DataValidationException("悠程公司卡开户银行长度在1-30个字符");

            if (string.IsNullOrWhiteSpace(model.ContractName))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "合同名称"));
            else
                if (!model.ContractName.ValidateLen(50))
                    throw new DataValidationException("合同名称长度在1-50个字符");

            if (model.ContractEndDate == null)
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "合同到期时间"));

            if (model.ContractEndDate < DateTime.Now)
                throw new DataValidationException("合同到期时间不能小于当前时间");

            if (model.ContractAttachmentList == null || model.ContractAttachmentList.Count() <= 0)
                throw new DataValidationException("请上传附件");

            model.ContractAttachmentList.ForEach((e) =>
            {
                if (string.IsNullOrWhiteSpace(e.Item2))
                    throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "合同存放地址"));

                if (string.IsNullOrWhiteSpace(e.Item1))
                    throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "合同文件名称"));

                if (!e.Item2.ValidateLen(500))
                    throw new DataValidationException("合同存放地址长度在1-500个字符");
            });

            if (string.IsNullOrWhiteSpace(model.AccountAdministrator))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "专线管理员"));
            else
                if (!model.AccountAdministrator.ValidateLen(20))
                    throw new DataValidationException("专线管理员长度在1-20个字符");

            if (string.IsNullOrWhiteSpace(model.AccountRelName))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "真实姓名"));
            else
                if (!model.AccountRelName.ValidateLen(20))
                    throw new DataValidationException("真实姓名长度在1-20个字符");

            if (string.IsNullOrWhiteSpace(model.AccountPhone))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "手机号码"));
            else
                if (!model.AccountPhone.ValidateLen(11))
                    throw new DataValidationException("手机号码长度在1-11个字符");

            #endregion

            var branch = this._baranchRepository.Find(c => c.ID == model.BranchId);
            if (branch.Type != Framework.Enums.BranchType.Branch)
            { throw new DataOperationPermissions("非分社不能使用该功能"); }

            if (_userRepository.GetModel().Any(p => p.Login.Equals(model.AccountAdministrator)
                && (p.Status == UserStatus.Normal || p.Status == UserStatus.Freeze)))
                throw new BusinessException("专线管理员已存在,请重新输入");

            if (_specialMainRepository.GetModel().Any(p => p.BranchId == model.BranchId && p.Status != SpecialStatus.AccountCancellation && p.Name == model.Name))
                throw new BusinessException("同一机构专线名称不能重复");

            var userPhone = this._userRepository.GetModel(c => c.Status != UserStatus.AccountCancellation && c.Phone == model.AccountPhone).Count();
            if (userPhone > 0)
                throw new BusinessException("专线管理员手机号码已被使用");

            string specialCode = CommonMethod.GetInstance.GenerateCode(SPECIALCODEHEADER);
            string contractCode = CommonMethod.GetInstance.GenerateCode(CONTRACTCODEHEADER);

            //重复处理
            while (_specialMainRepository.GetModel().Any(p => p.Code == specialCode))
                specialCode = CommonMethod.GetInstance.GenerateCode(SPECIALCODEHEADER);

            while (_contractRepository.GetModel().Any(p => p.Code == contractCode))
                contractCode = CommonMethod.GetInstance.GenerateCode(CONTRACTCODEHEADER);

            TransactionScopeNoMsdtc.UsingTransactionNoMsdtc(this._db, () =>
            {
                #region
                //专线基本信息
                Special tmp = new Special();
                tmp.Name = model.Name;
                tmp.BranchId = model.BranchId;
                tmp.Code = specialCode;
                tmp.Status = model.Status;
                tmp.ChargeName = model.ChargeName;
                tmp.ChargePhone = model.ChargePhone;
                tmp.ChargePaperType = model.ChargePaperType;
                tmp.ChargePaperNumber = model.ChargePaperNumber;
                tmp.ChargeBank = model.ChargeBank;
                tmp.ChargeBankNumber = model.ChargeBankNumber;
                tmp.CompanyBank = model.CompanyBank;
                tmp.CompanyNumber = model.CompanyNumber;
                tmp.EndDate = model.ContractEndDate;
                tmp.CreaterId = model.Creater;
                tmp.CreaterName = model.CreaterName;
                tmp.CreateTime = model.CreateTime;
                tmp.UpdaterId = model.Creater;
                tmp.UpdaterName = model.CreaterName;
                tmp.UpdateTime = model.CreateTime;
                //专线资金信息
                tmp.SpecialCapital = new SpecialCapital();
                this._specialMainRepository.Insert(tmp);

                //合同信息
                Contract contract = new Contract();
                contract.SpecialId = tmp.ID;
                contract.BranchId = model.BranchId;
                contract.Name = model.ContractName;
                contract.Code = contractCode;
                contract.Type = ContractType.SpecialLine;
                contract.Status = ContractStatus.Normal;
                contract.StartDate = model.ContractStartDate;
                contract.EndDate = model.ContractEndDate;
                contract.CreaterId = model.Creater;
                contract.CreateTime = model.CreateTime;
                contract.UpdaterId = model.Creater;
                contract.UpdateTime = model.CreateTime;
                //附件信息
                contract.Attachments = new List<Attachment>();
                model.ContractAttachmentList.ForEach((e) =>
                {
                    string suffix = e.Item1.Substring(e.Item1.LastIndexOf('.'), e.Item1.Length - e.Item1.LastIndexOf('.'));
                    contract.Attachments.Add(new Attachment()
                    {
                        Address = e.Item2,
                        CreateTime = model.CreateTime,
                        Name = e.Item1,
                        Suffix = suffix,
                        Type = AttachmentType.ContractAttachment
                    });
                });
                this._contractRepository.Insert(contract);

                //管理员账号信息
                User user = new User();
                user.Login = model.AccountAdministrator;
                user.PassWord = CommonMD5.getInstance().Get2MD5(BusinessConst._PASSWORD);
                user.Name = model.AccountRelName;
                user.Phone = model.AccountPhone;
                user.IsSpecialManager = true;
                user.Type = UserType.SpecialLine;
                user.SpecialId = tmp.ID;
                user.Status = UserStatus.Normal;
                user.CreaterId = model.Creater;
                user.CreateTime = model.CreateTime;
                user.UpdaterId = model.Creater;
                user.UpdateTime = model.CreateTime;
                #region 设置默认权限
                int value = (int)UserType.SpecialLine;
                var listMenu = _menuRepository.GetModelTracking().Where(p => ((p.UserMenu & value) == value)).ToList();
                user.Menus = listMenu;
                #endregion
                this._userRepository.Insert(user);
                #endregion
            });

        }

        /// <summary>
        /// 获取专线信息
        /// </summary>
        /// <param name="id">ID</param>
        /// <returns></returns>
        public Special GetSingleSpecial(int id)
        {
            #region valid
            if (id <= 0)
                throw new DataValidationException("请选择专线");
            #endregion

            var single = this._specialMainRepository.Find(c => c.ID == id);

            return single;
        }

        /// <summary>
        /// 编辑专线信息
        /// </summary>
        /// <param name="model">model</param>
        public void ModifySpecial(SpecialEditViewModel model)
        {
            #region valid
            if (model.ID <= 0)
                throw new DataValidationException("请选择专线");
            if (string.IsNullOrWhiteSpace(model.ChargePhone))
                throw new DataValidationException(string.Format(BusinessResourceMessage.PleaseInput, "专线负责人手机"));
            else
                if (!model.ChargePhone.ValidateLen(11))
                    throw new DataValidationException("负责人手机长度在1-11个字符");
            #endregion

            var single = this._specialMainRepository.GetModelTracking().Where(c => c.ID == model.ID).SingleOrDefault();
            if (single.Status != SpecialStatus.Normal)
                throw new BusinessException("专线状态异常");

            single.ChargePhone = model.ChargePhone;
            this._specialMainRepository.Update(single);
        }

        /// <summary>
        /// 销户
        /// </summary>
        /// <param name="id">ID</param>
        /// <param name="operateUserId">操作人ID</param>
        /// <param name="operateUserName">操作人名称</param>
        public void CancelSpecial(int id, int operateUserId)
        {
            if (id <= 0)
                throw new DataValidationException("请选择专线");

            var single = this._specialMainRepository.GetModelTracking().Include(c => c.SpecialCapital).FirstOrDefault(c => c.ID == id);
            if (single.Status == SpecialStatus.AccountCancellation)
                throw new BusinessException("该专线已销户,无法再次销户");

            //销户条件
            //发票信息无待开具、收款信息无待确认、付款信息无待确认、收票信息无待确认
            //已收款大于已开票、已收票大于已付款
            if (single.SpecialCapital.Gathering >= single.SpecialCapital.InvoiceSend)
            { }
            else { throw new BusinessException("总收款必须大于等于已开票额度"); }
            if (single.SpecialCapital.InvoiceCollect >= single.SpecialCapital.Payment)
            { }
            else { throw new BusinessException("已收票必须大于等于已付款"); }

            //发票
            var invoice = this._invoiceRepository.GetModel(c => c.SpecialId == id && c.Status == InvoiceStatus.WaitInvoice).Count();
            if (invoice > 0)
                throw new BusinessException("发票业务未完成");
            //收款
            var gathering = this._gatheringRepository.GetModel(c => c.SpecialId == id && c.Status == GatheringStatus.WaitVerify).Count();
            if (gathering > 0)
                throw new BusinessException("收款业务未完成");
            //付款
            var payment = this._paymentRepository.GetModel(c => c.SpecialId == id && c.Status == PaymentStatus.WaitVerify).Count();
            if (payment > 0)
                throw new BusinessException("付款业务未完成");

            //收票
            var collectInvoice = this._paymentRepository.GetModel(c => c.SpecialId == id).Select(c => c.CollectInvoice.Where(p => p.Status == CollectInvoiceStatus.WaitVerify)).Count();
            if (collectInvoice > 0)
                throw new BusinessException("收票业务未完成");

            TransactionScopeNoMsdtc.UsingTransactionNoMsdtc(this._db, () =>
           {
               single.Status = SpecialStatus.AccountCancellation;
               this._specialMainRepository.Update(single);

               //专线下的账号销户
               var user = this._userRepository.GetModelTracking().Include(c => c.Special).Where(c => c.Special.ID == id);
               if (user != null)
               {
                   foreach (var item in user)
                   {
                       item.Status = UserStatus.AccountCancellation;
                   }
               }
               this._userRepository.Update(user);
           });
        }

        /// <summary>
        /// 获取专线详情
        /// </summary>
        /// <param name="id">ID</param>
        /// <returns></returns>
        public SpecialDetailViewModel GetDetailSpecial(int id)
        {
            if (id <= 0)
                throw new DataValidationException("请选择专线");
            var single = this._specialMainRepository.GetModel().Include(c => c.SpecialCapital).Where(c => c.ID == id).FirstOrDefault();
            if (single == null)
                throw new BusinessException("专线不存在");

            SpecialDetailViewModel detail = new SpecialDetailViewModel();
            #region
            detail.ID = single.ID;
            detail.UpdaterName = single.UpdaterName;
            detail.UpdateTime = single.UpdateTime;
            detail.Name = single.Name;
            detail.Code = single.Code;
            detail.ChargeName = single.ChargeName;
            detail.ChargePhone = single.ChargePhone;
            detail.ChargePaperType = single.ChargePaperType;
            detail.ChargePaperNumber = single.ChargePaperNumber;
            detail.ChargeBank = single.ChargeBank;
            detail.ChargeBankNumber = single.ChargeBankNumber;
            detail.CompanyBank = single.CompanyBank;
            detail.CompanyNumber = single.CompanyNumber;
            detail.Status = single.Status;
            detail.EndDate = single.EndDate;
            detail.CreaterName = single.CreaterName;
            detail.CreateTime = single.CreateTime;
            detail.Balance = single.SpecialCapital.Balance;
            detail.Profit = single.SpecialCapital.Profit;
            detail.Gathering = single.SpecialCapital.Gathering;
            detail.Payment = single.SpecialCapital.Payment;
            detail.InvoiceSend = single.SpecialCapital.InvoiceSend;
            detail.InvoiceCollect = single.SpecialCapital.InvoiceCollect;

            //合同信息
            var list = this._contractRepository.GetModel().Include(c => c.Creater).Include(c => c.Attachments).Include(c => c.SellerSupplier).Where(c => c.SpecialId == single.ID && (c.Status == ContractStatus.Normal || c.Status == ContractStatus.Renewal)).ToList();
            //专线合同信息
            var contract = list.Where(c => c.Type == ContractType.SpecialLine).FirstOrDefault();
            if (contract != null)
            {
                detail.TenureUserName = contract.Creater.Name;
                detail.TenureTime = contract.CreateTime;
                detail.ContractEndDate = contract.EndDate;
                detail.ContractCode = contract.Code;
                detail.ContractName = contract.Name;
            }
            detail.ContractAttachment = new List<Tuple<string, string>>();
            if (contract.Attachments != null && contract.Attachments.Count() > 0)
            {
                foreach (var item in contract.Attachments)
                {
                    detail.ContractAttachment.Add(new Tuple<string, string>(item.Name, item.Address));
                }
            }
            detail.SellerInfo = new List<SellerSupplierViewModel>();
            detail.SupplierInfo = new List<SellerSupplierViewModel>();

            //销售商信息
            var seller = list.Where(c => c.Type == ContractType.Seller).ToList();
            //供应商信息
            var supper = list.Where(c => c.Type == ContractType.Supplier).ToList();

            if (seller != null && seller.Count() > 0)
            {
                seller.ForEach((c) =>
                {
                    if (c.SellerSupplier.Status)
                    {
                        detail.SellerInfo.Add(new SellerSupplierViewModel()
                        {
                            ContractEndDate = c.EndDate,
                            ContractName = c.Name,
                            Name = c.SellerSupplier.Name,
                            Status = c.SellerSupplier.Status,
                            ChargeName = c.SellerSupplier.ChargeName,
                            Phone = c.SellerSupplier.Phone
                        });
                    }
                });
            }
            if (supper != null && supper.Count() > 0)
            {
                supper.ForEach((c) =>
                {
                    if (c.SellerSupplier.Status)
                    {
                        detail.SupplierInfo.Add(new SellerSupplierViewModel()
                        {
                            ContractEndDate = c.EndDate,
                            ContractName = c.Name,
                            Name = c.SellerSupplier.Name,
                            Status = c.SellerSupplier.Status,
                            ChargeName = c.SellerSupplier.ChargeName,
                            Phone = c.SellerSupplier.Phone
                        });
                    }
                });
            }
            #endregion

            return detail;
        }
    }
}
